package com.wll.springbootminiomaster.controller;

import cn.hutool.core.util.StrUtil;
import com.wll.springbootminiomaster.common.util.MinioUtil;
import com.wll.springbootminiomaster.common.util.ResponseJson;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件操作
 */
@RestController
@RequestMapping(value = "/file")
public class FileController {

    @Autowired
    MinioUtil minioUtil;


    /**
     * 文件重新命名
     *
     * @param fileOldName
     * @return
     */
    public static String rename(String fileOldName) {
        String fileNewName = "";
        // 重新命名文件名称
        String[] split = fileOldName.split("\\.");
        if (split.length > 1) {
            return split[0] + "_" + System.currentTimeMillis() + "." + split[1];
        } else {
            throw new RuntimeException("文件名有误");
        }
    }

    /**
     * 上传一个文件
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param folderName 文件夹
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    public ResponseJson fileupload(@RequestParam MultipartFile file, @RequestParam String bucketName, @RequestParam(required = false) String folderName) throws Exception {
        minioUtil.createBucket(bucketName);
        String fileName = file.getOriginalFilename();
//       // 重新命名文件名称
//       fileName = rename(fileName);
        if (StrUtil.isNotBlank(folderName)) {
            minioUtil.uploadFile(file.getInputStream(), bucketName, folderName + "/" + fileName);
        } else {
            minioUtil.uploadFile(file.getInputStream(), bucketName, fileName);
        }
        return ResponseJson.success();
    }

    /**
     * 批量上传文件
     *
     * @param multipartFile 文件
     * @param bucketName    桶名称
     * @param folderName    文件夹
     * @return
     */
    @RequestMapping(value = "/batchUploadFile", method = RequestMethod.POST)
    public ResponseJson batchUploadFile(MultipartFile[] multipartFile, @RequestParam String bucketName, @RequestParam(required = false) String folderName) {
        for (MultipartFile file : multipartFile) {
            String fileName = file.getOriginalFilename();
//            // 重新命名文件名称
//           fileName = rename(fileName);
            InputStream in = null;
            try {
                in = file.getInputStream();
                if (StrUtil.isNotBlank(folderName)) {
                    minioUtil.uploadFile(file.getInputStream(), bucketName, folderName + "/" + fileName);
                } else {
                    minioUtil.uploadFile(file.getInputStream(), bucketName, file.getOriginalFilename());
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ResponseJson.error();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return ResponseJson.success();
    }

    /**
     * 列出所有的桶
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/listBuckets", method = RequestMethod.GET)
    public ResponseJson listBuckets() throws Exception {
        return ResponseJson.success(minioUtil.listBuckets());
    }

    /**
     * 递归列出一个桶中的所有文件和目录
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/listFiles", method = RequestMethod.GET)
    public ResponseJson listFiles(@RequestParam String bucketName) throws Exception {
        return ResponseJson.success(minioUtil.listFiles(bucketName));
    }

    /**
     * 下载一个文件
     *
     * @param bucketName
     * @param fileName
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/downloadFile", method = RequestMethod.GET)
    public void downloadFile(@RequestParam String bucketName, @RequestParam String fileName, HttpServletResponse response) throws Exception {
        InputStream stream = minioUtil.download(bucketName, fileName);
        ServletOutputStream output = response.getOutputStream();
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), "UTF-8"));
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        IOUtils.copy(stream, output);
    }

    /**
     * 批量下载
     *
     * @param fileNames   多个文件名称
     * @param bucketNames 桶名称
     * @param zipName     压缩包名称
     * @param res
     * @param req
     */
    @RequestMapping(value = "/batchDownloadFile", method = RequestMethod.GET)
    public void batchDownloadFile(String fileNames, String bucketNames, @RequestParam(required = false) String zipName, HttpServletResponse res, HttpServletRequest req) {
        try {
            if (StrUtil.isEmpty(fileNames) || StrUtil.isEmpty(bucketNames)) {
                return;
            }
            if (StrUtil.isEmpty(zipName)) {
                zipName = System.currentTimeMillis() + "";
            }
            String[] fileNameArray = fileNames.split(",");
            String[] bucketNameArray = bucketNames.split(",");
            res.reset();
            BufferedOutputStream bos = new BufferedOutputStream(res.getOutputStream());
            ZipOutputStream out = new ZipOutputStream(bos);
            out.setMethod(ZipOutputStream.DEFLATED);
            res.setHeader("Access-Control-Allow-Origin", "*");
            for (int i = 0; i < fileNameArray.length; i++) {
                String bucketName = bucketNameArray[i];
                String fileName = fileNameArray[i];
                InputStream object = minioUtil.download(bucketName, fileName);
                byte buf[] = new byte[1024];
                int length = 0;
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                res.setContentType("application/force-download");
                res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
                res.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoding(zipName, req) + ".zip");
                fileName = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length());
                out.putNextEntry(new ZipEntry(System.currentTimeMillis() + "_" + fileName));
                while ((length = object.read(buf)) > 0) {
                    out.write(buf, 0, length);
                }
            }
            out.close();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置不同浏览器编码
     *
     * @param fileName 文件名称
     * @param request  请求对象
     */
    public static String filenameEncoding(String fileName, HttpServletRequest request) throws UnsupportedEncodingException {
        // 获得请求头中的User-Agent
        String agent = request.getHeader("User-Agent");
        // 根据不同的客户端进行不同的编码
        if (agent.contains("MSIE")) {
            // IE浏览器
            fileName = URLEncoder.encode(fileName, "utf-8");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            fileName = URLEncoder.encode(fileName, "utf-8");
        }
        return fileName;
    }

    /**
     * 删除一个文件
     *
     * @param bucketName
     * @param fileName
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/deleteFile", method = RequestMethod.GET)
    public ResponseJson deleteFile(@RequestParam String bucketName, @RequestParam String fileName) throws Exception {
        minioUtil.deleteObject(bucketName, fileName);
        return ResponseJson.success();
    }


    /**
     * 删除多个文件
     *
     * @param bucketNames
     * @param fileNames
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/batchDeleteFile", method = RequestMethod.GET)
    public ResponseJson batchDeleteFile(@RequestParam String bucketNames, @RequestParam String fileNames) throws Exception {
        if (StrUtil.isEmpty(fileNames) || StrUtil.isEmpty(bucketNames)) {
            return ResponseJson.error("参数错误");
        }
        String[] fileNameArray = fileNames.split(",");
        String[] bucketNameArray = bucketNames.split(",");
        for (int i = 0; i < fileNameArray.length; i++) {
            String bucketName = bucketNameArray[i];
            String fileName = fileNameArray[i];
            minioUtil.deleteObject(bucketName, fileName);
        }
        return ResponseJson.success();
    }

    /**
     * 删除一个桶
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/deleteBucket", method = RequestMethod.GET)
    public ResponseJson deleteBucket(@RequestParam String bucketName) throws Exception {
        minioUtil.deleteBucket(bucketName);
        return ResponseJson.success();
    }


    /**
     * 复制一个文件
     *
     * @param sourceBucket 源桶
     * @param sourceObject 源文件
     * @param targetBucket 目标桶
     * @param targetObject 目标文件
     * @return
     * @throws Exception
     */
    @GetMapping("/copyObject")
    public ResponseJson copyObject(@RequestParam String sourceBucket, @RequestParam String sourceObject, @RequestParam String targetBucket, @RequestParam String targetObject) throws Exception {
        minioUtil.copyObject(sourceBucket, sourceObject, targetBucket, targetObject);
        return ResponseJson.success();
    }

    /**
     * 获取文件信息
     *
     * @param bucketName
     * @param fileName
     * @return
     * @throws Exception
     */
    @GetMapping("/getObjectInfo")
    public ResponseJson getObjectInfo(@RequestParam String bucketName, @RequestParam String fileName) throws Exception {
        return ResponseJson.success(minioUtil.getObjectInfo(bucketName, fileName));
    }

    /**
     * 获取一个连接以供下载 预览
     *
     * @param bucketName 桶
     * @param fileName   文件名
     * @param expires    预览到期时间（小时）
     * @return
     * @throws Exception
     */
    @GetMapping("/getPresignedObjectUrl")
    public ResponseJson getPresignedObjectUrl(@RequestParam String bucketName, @RequestParam String fileName, @RequestParam Integer expires) throws Exception {
        return ResponseJson.success(minioUtil.getPreviewUrl(bucketName, fileName, expires));
    }

    /**
     * 获取minio中所有的文件
     *
     * @return
     * @throws Exception
     */
    @GetMapping("/listAllFile")
    public ResponseJson listAllFile() throws Exception {
        return ResponseJson.success(minioUtil.listAllFile());
    }


}